package com.iqiyi.pps.epg.core.utils;

import com.alibaba.fastjson.JSON;
import com.iqiyi.pps.epg.core.model.carousel.AutoCarouselEpisodeLibrary;
import com.iqiyi.pps.epg.core.model.carousel.CarouselBase;
import com.iqiyi.pps.epg.core.model.carousel.ProgramLegoData;
import com.iqiyi.pps.epg.core.model.carousel.ProgramQipuData;
import com.iqiyi.pps.epg.core.model.channel.ChannelBase;
import com.iqiyi.pps.epg.core.model.channel.SearchSettingConfig;
import com.iqiyi.pps.epg.core.model.program.ProgramData;
import com.iqiyi.pps.epg.core.model.remind.MailRemind;
import com.iqiyi.pps.epg.core.service.channel.ChannelService;
import com.iqiyi.pps.epg.core.service.notifymail.NotifyMailService;
import com.iqiyi.pps.epg.core.service.remind.MailRemindService;
import com.iqiyi.pps.epg.core.utils.mail.MailConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.util.*;

/**
 * Created by karkarrotxu on 2015/6/9.
 */
public final class CarouselAssistUtil {
    private static ChannelService cService = null;
    private static MailRemindService mailRemindService = null;
    private static NotifyMailService notifyMailService = null;
    private static Logger logger = LoggerFactory.getLogger(CarouselAssistUtil.class);

    //603636201
    private CarouselAssistUtil() {
    }

//    public static void main(String[] args) {
//        CarouselBase carouselBase = new CarouselBase();
//        // carouselBase.setQipuId(90289001L);
//        carouselBase.setQipuId(603636201L);
//        carouselBase.setFollowNum(1);
//        carouselBase.setTotalNum(700);
//        carouselBase.setFatherId(1L);
//        carouselBase.setStartNum(1);
//        carouselBase.setId(30L);
//        carouselBase.setStartTime(new Timestamp(System.currentTimeMillis()));
//        ChannelBase cBase = new ChannelBase();
//        cBase.setId(1L);
//        cBase.setAllowPopups(1);
//        cBase.setQitanId(0L);
//
//        List<ChannelBase> channelBaseList = new ArrayList<ChannelBase>();
//        channelBaseList.add(cBase);
//        List<ProgramQipuData> list = create(carouselBase, channelBaseList, null, 7);
//        System.out.println("===" + list.size());
//        System.out.println(JSONArray.toJSON(list));
//
//    }


    public static List<ProgramQipuData> queryForData(List<Long> qipuIdList, ChannelBase cBase, Map<Long, ProgramQipuData> cacheMap, long carouselBaseId) {
        List<ProgramQipuData> retList = new ArrayList<ProgramQipuData>();
        if (cacheMap == null) {
            cacheMap = new HashMap<Long, ProgramQipuData>();
        }
        ProgramQipuData childEntity = null;
        long currentAddTime = System.currentTimeMillis();
        ProgramData original = null;
        logger.info("[queryForData] begin query data carouselBaseId: " + carouselBaseId);
        for (Long childQipuId : qipuIdList) {
            childEntity = cacheMap.get(childQipuId);
            if (childEntity == null) {
                childEntity = ApiQipuUtil.queryByQipuIdAndCheck(childQipuId.longValue(), getCService().getSearchConfig(cBase.getId()), cBase);
                original = childEntity.getOriginal();
                original.setRuleId((int) carouselBaseId);
                original.setFatherId(cBase.getId().intValue());
                original.setAddTime(new Timestamp(currentAddTime));
                original.setLive(ProgramData.TYPE_DEMAND);
                original.setType(7);//轮播台节目
                fillDefaultValue(cBase, childEntity);
                cacheMap.put(childQipuId, childEntity);
            }
            childEntity = getProgramDataInstance(childEntity);
            retList.add(childEntity);
        }
        return retList;
    }


    private static int checkCreateDays(CarouselBase carouselBase, Date createStartDate, int createDays) {
        Date ruleEndTime = new Date(carouselBase.getEndTime().getTime());
        long minCheckTime = ruleEndTime.getTime();
        int betweenDays = DateTimeUtil.getBetweenDays(DateTimeUtil.transShortFormat(minCheckTime), DateTimeUtil.transShortFormat(createStartDate.getTime()));
        if (minCheckTime < createStartDate.getTime()) {
            if (betweenDays == 0) {
                createDays = 1; //lastDay;
            } else {
                createDays = -1; // invalid
            }
        } else {
            if (createDays > betweenDays) {
                createDays = betweenDays + 1;
            }
        }

        return createDays;
    }

    public static List<ProgramQipuData> create(CarouselBase carouselBase, ChannelBase cBase, String createStartTime,
                                               int createDays) {
        Long qipuId = carouselBase.getQipuId();
        if (qipuId == null || qipuId < 1) {
            return null;
        }
        if (cBase == null) {
            logger.debug("[CarouselAssistUtil][create] CarouselBase is null ");
            return null;
        }
        Date createStartDate = null;
        if (createStartTime == null) {
            createStartDate = new Date(carouselBase.getStartTime().getTime());
        } else {

            if (createStartTime.length() == 10) {
                createStartDate = new Date(DateTimeUtil.parseShortFormat(createStartTime));
            } else if (createStartTime.length() == 19) {
                createStartDate = new Date(DateTimeUtil.parseLongFormat(createStartTime));
            }
        }
        if (!carouselBase.checkIsRepeat()) {
            createDays = checkCreateDays(carouselBase, createStartDate, createDays);
        }

        if (createDays < 1) {
            if (createDays == -1) {
                logger.info("[CarouselAssistUtil] [createStartTime={}]", createStartTime);
            }
            logger.warn("[CarouselAssistUtil] invalid createDays={}", createDays);
            return null;
        }

        SearchSettingConfig config = getCService().getSearchConfig(carouselBase.getFatherId());
        String cacheKey = carouselBase.getFatherId() + "_" + qipuId;
        AlbumLegoDataCache albumLegoDataCache = ApiLegoUtil.getValidCache(cacheKey);
        List<Long> children = null;
        AlbumLegoData albumLegoData = null;
        if (albumLegoDataCache == null) {
            albumLegoData = ApiLegoUtil.queryAlbumId(qipuId);
            children = ApiLegoUtil.collectValidProgram00(albumLegoData, config);
            ApiLegoUtil.addLegoDataCache(cacheKey, albumLegoData, children);
        } else {
            albumLegoData = albumLegoDataCache.getAlbumLegoData();
            children = albumLegoDataCache.getChildren();
        }
        // List<Long> children = ApiLegoUtil.getEpisodeChildren(qipuId);
        if (children == null) {
            carouselBase.setStatus(CarouselBase.ILLEGAL_STATUS);
            logger.warn("[CarouselAssistUtil] lego接口未取到数据,qipuId:{}", carouselBase.getQipuId());
            return null;
        }
        if (children.isEmpty()) {
            logger.warn("[CarouselAssistUtil] 未取到数据,qipuId:{}", carouselBase.getQipuId());
            return null;
        }
        logger.info("[CarouselAssistUtil] ready carouselBase totalNum:" + carouselBase.getTotalNum() + " actualNum:" + carouselBase.getActualNum());
        if (children.size() != carouselBase.getActualNum()) {
            logger.info("[CarouselAssistUtil] [create] actual num has change old:" + carouselBase.getActualNum() + " new :" + children.size());
            carouselBase.setActualNum(children.size());
            carouselBase.setNeedUpdate(true);
        }
        if (carouselBase.getTotalNum() < carouselBase.getActualNum()) {
            logger.info("[CarouselAssistUtil] [create] actual:{} gt totalNum:{} | set actual = totalNum", carouselBase.getActualNum(), carouselBase.getTotalNum());
            carouselBase.setActualNum(carouselBase.getTotalNum());
            carouselBase.setNeedUpdate(true);
        }

        if (carouselBase.checkIsFollow()) {
//            if (carouselBase.getActualNum() == carouselBase.getLastCreatedNo()) {
//                logger.info("[CarouselAssistUtil] [create] actualnum equals lastCreatedNo, no new data carouselBaseId:" + carouselBase.getId());
//                return null;
//            }
        } else if (carouselBase.checkIsRepeat()) {
            if (carouselBase.getActualNum() < carouselBase.getTotalNum()) {
                logger.info("[CarouselAssistUtil] [create] actualnum lt totalNum, error data carouselBaseId:" + carouselBase.getId());
                return null;
            }
        } else {
            if (albumLegoData.getReadTotalCount() > albumLegoData.getChildrenNum()) {
                doSendCarouselWarnMail(carouselBase, cBase, albumLegoData, createStartTime);
            }
            if (carouselBase.getActualNum() <= carouselBase.getLastCreatedNo()) {
                logger.info("[CarouselAssistUtil] [create][normal Type] actualnum lt lastCreatedNo, error data carouselBaseId:" + carouselBase.getId());
                return null;
            }
        }

        int limitNum = 0;
        if (carouselBase.checkIsFollow()) {
            limitNum = carouselBase.getTotalNum();
        } else {
            limitNum = carouselBase.getActualNum();
        }
        if (limitNum == 0) {
            logger.debug("[CarouselAssistUtil] carouselBase limitNum is zero ");
            return null;
        }
        CalculateResult result = null;
        try {
            result = calculateCreateResult(carouselBase, limitNum, createStartDate, createDays);
        } catch (Exception e) {
            logger.error("[CarouselAssistUtil][create][carouselId:"+carouselBase.getId()+"][error={}]", e);
        }
        List<ProgramQipuData> retList = null;
        //    boolean followCreate = carouselBase.getFollowedStatus() == 1 && carouselBase.getTotalNum() > carouselBase.getActualNum();
        boolean followCreate = carouselBase.checkIsFollow();
        if (followCreate) {
            retList = createFollow(carouselBase, cBase, createStartDate, children, result);
        } else {
            retList = createNoFollow(carouselBase, cBase, createStartDate, children, result);
        }
        if (retList != null && retList.size() > 0) {
            if (!carouselBase.checkIsFollow()) {
                carouselBase.setLastCreatedNo(result.getEndNum());
                carouselBase.setLastCreatedQipuId(children.get(carouselBase.getLastCreatedNo() - 1));
            }
        }
        return retList;
    }

    private static void doSendCarouselWarnMail(CarouselBase carouselBase, ChannelBase cBase, AlbumLegoData albumLegoData, String createStartTime) {
        MailRemind mailRemind = getMailService().getMailRemind("Carousel_Episode_Num_Warn", carouselBase.getId() + "");
        Timestamp endRange = mailRemind.getEndTime();
        Timestamp now = new Timestamp(System.currentTimeMillis());
        if (endRange != null && now.before(endRange)) {
            return;
        }
        if (endRange == null) {
            endRange = new Timestamp(now.getTime() + DateTimeUtil.DAY_TIME);
        } else {
            endRange = new Timestamp(endRange.getTime() + DateTimeUtil.DAY_TIME);
        }

        Map<String, String> map = new HashMap<String, String>();
        map.put(MailConstant.C_NAME, cBase.getName());
        map.put(MailConstant.C_QIPU_ID, cBase.getQipuId() + "");
        map.put(MailConstant.SHOW_NAME, carouselBase.getShowName());
        map.put(MailConstant.CAROUSEL_QIPU_ID, carouselBase.getQipuId() + "");
        map.put("totalCount", albumLegoData.getReadTotalCount() + "");
        map.put("childrenNum", albumLegoData.getChildrenNum() + "");
        map.put(MailConstant.ASSIGN_TOS,carouselBase.getOpUser());
        getNotifyMailService().addMailAsyncTask(0, MailContentUtil.ContentType.LB_EPISODE_NUM_ERROR.getTypeIndex(), map);
        getMailService().saveMailHistory(mailRemind, MailContentUtil.ContentType.LB_EPISODE_NUM_ERROR.toString(), "", "", endRange);
    }


    public static List<ProgramQipuData> createFollow(CarouselBase carouselBase, ChannelBase cBase, Date createStartDate, List<Long> children, CalculateResult result) {
        if (carouselBase.getItemTime() == 0) {
            long queryFirstQipuId = children.get(0).longValue();
            ProgramQipuData firstData = ApiQipuUtil.queryByQipuIdAndCheck(queryFirstQipuId, getCService().getSearchConfig(cBase.getId()), cBase);
            if (firstData.isIllegal()) {
                logger.error("[createFollow] fail to create first follow data qpuid:" + queryFirstQipuId);
                //  return null;
            }
            carouselBase.setItemTime(firstData.getDuration());
            carouselBase.setNeedUpdate(true);
        }
        int actualEndLimit = result.getStartNum() + result.getLength();
        List<ProgramQipuData> retList = new ArrayList<ProgramQipuData>();
        ProgramQipuData temple = null;
        ProgramData original = null;
        long currentAddTime = System.currentTimeMillis();
        for (int i = result.getStartNum(); i < actualEndLimit; i++) {
            temple = new ProgramQipuData();
            temple.setDuration(carouselBase.getItemTime());
            original = temple.getOriginal();
            original.setRuleId(carouselBase.getId().intValue());
            original.setFatherId(cBase.getId().intValue());
            original.setAddTime(new Timestamp(currentAddTime));
            original.setLive(ProgramData.TYPE_DEMAND);
            original.setType(7);//轮播台节目
            original.setPname(carouselBase.getShowName() + " " + i);
            fillDefaultValue(cBase, temple);
            retList.add(temple);
        }
        if (retList.size() > 0) {
            fillProgramTime(carouselBase, retList, createStartDate);
        }
        return retList;
    }

    public static List<ProgramQipuData> createNoFollow(CarouselBase carouselBase, ChannelBase cBase, Date createStartDate, List<Long> children, CalculateResult result) {
        int actualEndLimit = result.getStartNum() + result.getLength();
        List<Long> retQipuIdList = new ArrayList<Long>();
        int temp = -1;
        for (int i = result.getStartNum(); i < actualEndLimit; i++) {
            temp = i;
            while (temp > carouselBase.getActualNum()) {
                temp -= carouselBase.getActualNum();
            }
            retQipuIdList.add(children.get(temp - 1));
        }
        Map<Long, ProgramQipuData> cacheMap = new HashMap<Long, ProgramQipuData>();
        List<ProgramQipuData> retList = null;
        logger.debug("[CarouselAssistUtil][create] start queryChild  " + children.size());
        if (children.size() > 0) {
            retList = queryForData(retQipuIdList, cBase, cacheMap, carouselBase.getId());
            if (retList != null) {
                fillProgramTime(carouselBase, retList, createStartDate);
                List<Long> illegalList = fetchIllegalData(retList);
                if (illegalList.size() > 0) {
                    doSendIllegalRemind(illegalList, carouselBase, createStartDate);
                }
            }
        }
        return retList;
    }

    private static ChannelService getCService() {
        if (cService == null) {
            cService = (ChannelService) ApplicationContextUtil.getBean(ChannelService.class);
        }
        return cService;
    }

    private static MailRemindService getMailService() {
        if (mailRemindService == null) {
            mailRemindService = (MailRemindService) ApplicationContextUtil.getBean(MailRemindService.class);
        }
        return mailRemindService;
    }

    private static NotifyMailService getNotifyMailService() {
        if (notifyMailService == null) {
            notifyMailService = (NotifyMailService) ApplicationContextUtil.getBean(NotifyMailService.class);
        }
        return notifyMailService;
    }

    private static void doSendIllegalRemind(List<Long> illegalList, CarouselBase carouselBase, Date createStartDate) {
        ChannelService service = getCService();
        if (service == null) {
            logger.error("[doSendIllegalRemind] fail to get channelService [carouselBaseId={}]", carouselBase.getId());
            return;
        }
        ChannelBase channelBase = service.getChannelBase(carouselBase.getFatherId());
        if (channelBase == null) {
            logger.error("[doSendIllegalRemind] fail to get channelBase [carouselBase fatherId={}]", carouselBase.getFatherId());
            return;
        }
        Map<String, String> map = new HashMap<String, String>();

        map.put(MailConstant.C_NAME, channelBase.getName());
        map.put(MailConstant.C_QIPU_ID, "" + channelBase.getQipuId());
        map.put(MailConstant.SHOW_NAME, carouselBase.getShowName());
        map.put("createStartDate", DateTimeUtil.transShortFormat(createStartDate.getTime()));
        map.put(MailConstant.CAROUSEL_QIPU_ID, "" + carouselBase.getQipuId());
        map.put(MailConstant.P_QIPU_IDS, illegalList.toString().replaceAll("\\[|\\]|\\s", ""));

        String title = String.format(MailContentUtil.ILLEGAL_REMIND_TITLE, channelBase.getName());
        String[] tos = new String[]{carouselBase.getOpUser()};
        String content = MailContentUtil.getContent(MailContentUtil.ContentType.ILLEGAL_REMIND_ERROR, map);
        SendMailUtils.send(title, tos, content);
    }

    private static void fillProgramTime(CarouselBase carouselBase, List<ProgramQipuData> retList, Date createStartDate) {
        int count = 0;
        Calendar carouselStart = Calendar.getInstance();
        carouselStart.setTimeInMillis(carouselBase.getStartTime().getTime());
        Calendar createStart = Calendar.getInstance();
        createStart.setTimeInMillis(createStartDate.getTime());
        ProgramQipuData childEntity = null;
        long dayEndTime = DateTimeUtil.getDayEndTime(createStart.getTimeInMillis());
        long dayStarTime = DateTimeUtil.getZeroTime(createStart.getTimeInMillis());
        for (int i = 0; i < retList.size(); i++) {
            childEntity = retList.get(i);
            childEntity.setAlbumName(carouselBase.getShowName());
            if (count % carouselBase.getFollowNum() == 0) {
                createStart.set(Calendar.HOUR_OF_DAY, carouselStart.get(Calendar.HOUR_OF_DAY));
                createStart.set(Calendar.MINUTE, carouselStart.get(Calendar.MINUTE));
                createStart.set(Calendar.SECOND, carouselStart.get(Calendar.SECOND));
                createStart.set(Calendar.MILLISECOND, carouselStart.get(Calendar.MILLISECOND));
            }
            childEntity.setStartTime(createStart.getTimeInMillis());
            createStart.add(Calendar.SECOND, childEntity.getDuration());
            if (createStart.getTimeInMillis() > dayEndTime) {
                createStart.setTimeInMillis(dayEndTime);
            }
            childEntity.setEndTime(createStart.getTimeInMillis());
            count++;
            if (count % carouselBase.getFollowNum() == 0) {
                dayStarTime += DateTimeUtil.DAY_TIME;
                dayEndTime += DateTimeUtil.DAY_TIME;
                createStart.setTimeInMillis(dayStarTime);
            }
        }
    }

    public static CalculateResult calculateCreateResult(CarouselBase carouselBase, int limitNum, Date createStartDate, int createDays) {
        int length = 0;
        logger.info("[CarouselAssistUtil][calculateCreateResult] start");

        long startZeroTime = DateTimeUtil.getZeroTime(carouselBase.getStartTime().getTime());
        long createZeroTime = DateTimeUtil.getZeroTime(createStartDate.getTime());
        int startNum = 0;
        int gapDay = (int) ((createZeroTime - startZeroTime) / 86400000);
        if (carouselBase.getLastCreatedNo() == 0) {
            startNum = carouselBase.getStartNum() + gapDay * carouselBase.getFollowNum();
        } else {
            startNum = carouselBase.getLastCreatedNo() + 1;
            if (carouselBase.getFollowedStatus() == 1) {
                startNum = carouselBase.getStartNum() + gapDay * carouselBase.getFollowNum();
            }
        }

        while (startNum > limitNum) {
            startNum -= limitNum;
        }


        int endNum = startNum + createDays * carouselBase.getFollowNum() - 1;
        int loop = 0;
        boolean repeatedActive = carouselBase.checkIsRepeat() && carouselBase.getTotalNum() == limitNum;
        if (repeatedActive) {
            length = createDays * carouselBase.getFollowNum();
            while (endNum > limitNum) {
                loop++;
                endNum -= limitNum;
            }
        } else {
            if (endNum > limitNum) {
                endNum = limitNum;
            }
            length = endNum - startNum + 1;
        }
        CalculateResult result = new CalculateResult();
        result.setStartNum(startNum);
        result.setEndNum(endNum);
        result.setLength(length);
        result.setLoop(loop);
        logger.info("[CarouselAssistUtil][calculateCreateResult] end ;" + JSON.toJSON(result));
        return result;
    }

    public static ProgramQipuData getProgramDataInstance(ProgramQipuData childEntity) {
        if (null == childEntity) {
            return null;
        }
        if (!childEntity.hasInstance()) {
            childEntity.addInstanceCount();
            return childEntity;
        } else {
            ProgramQipuData returnVal = new ProgramQipuData();
            returnVal.setDuration(childEntity.getDuration());
            ProgramData original = childEntity.getOriginal();
            ProgramData newData = returnVal.getOriginal();

            newData.setFatherId(original.getFatherId());
            newData.setFreeStatus(original.getFreeStatus());
            newData.setPname(original.getPname());
            newData.setLive(Integer.valueOf(original.getLive()));
            newData.setType(original.getType());
            newData.setRuleId(original.getRuleId());
            newData.setCarouselEpisode(original.getCarouselEpisode());
            newData.setDescription(original.getDescription());
            newData.setAllowComment(original.getAllowComment());
//            newData.setAllowPopups(original.getAllowPopups());
            newData.setBossStatus(original.getBossStatus());
            newData.setDefaultLogoUrl(original.getDefaultLogoUrl());
            newData.setMemberFree(original.getMemberFree());
            newData.setMemberOnly(original.getMemberOnly());
            newData.setFreeStatus(original.getFreeStatus());
            newData.setQitanId(original.getQitanId());
            newData.setQiyiExclusive(original.getQiyiExclusive());
            newData.setQiyiProduct(original.getQiyiProduct());
            newData.setAddTime(new Timestamp(original.getAddTime().getTime()));
            newData.setIllegalStatus(original.getIllegalStatus());
            newData.setReferContentType(original.getReferContentType());
            newData.setAlbumName(original.getAlbumName());
            return returnVal;
        }
    }

    public static ProgramLegoData getProgramLegoDataInstance(ProgramLegoData childEntity) {
        if (!childEntity.hasInstance()) {
            childEntity.addInstanceCount();
            return childEntity;
        } else {
            ProgramLegoData returnVal = new ProgramLegoData();
            AutoCarouselEpisodeLibrary original = childEntity.getOriginal();
            AutoCarouselEpisodeLibrary newData = returnVal.getOriginal();
            newData.setDuration(original.getDuration());
            newData.setFatherId(original.getFatherId());
            return returnVal;
        }
    }


    public static void fillDefaultValue(ChannelBase channelBase, ProgramQipuData childEntity) {
        ProgramData original = childEntity.getOriginal();
//        original.setAllowPopups(channelBase.getAllowPopups());
        original.setMemberFree(1);
        original.setMemberOnly(0);
        original.setFreeStatus(1);
        original.setBossStatus(ProgramData.FREE);
        original.setQitanId(channelBase.getQitanId());
        original.setMaxPlaybackPeriod(channelBase.getMaxPlaybackPeriod());
        original.setSubjectUrl(channelBase.getSubjectUrl());
        original.setAllowComment(channelBase.getShouldDisplay());
    }

    private static List<Long> fetchIllegalData(List<ProgramQipuData> retList) {
        List<Long> illegalList = new ArrayList<Long>();
        for (ProgramQipuData data : retList) {
            if (data.isIllegal()) {
                illegalList.add(data.getOriginal().getCarouselEpisode());
            }
        }
        return illegalList;
    }


    static class CalculateResult {
        private int loop;
        private int startNum;
        private int endNum;
        private int length;

        public int getLoop() {
            return loop;
        }

        public void setLoop(int loop) {
            this.loop = loop;
        }

        public int getStartNum() {
            return startNum;
        }

        public void setStartNum(int startNum) {
            this.startNum = startNum;
        }

        public int getEndNum() {
            return endNum;
        }

        public void setEndNum(int endNum) {
            this.endNum = endNum;
        }

        public int getLength() {
            return length;
        }

        public void setLength(int length) {
            this.length = length;
        }

    }

}

